package org.pfc.porlapatilla.repositories;

import java.util.List;

import org.pfc.porlapatilla.model.Message;
import org.pfc.porlapatilla.model.Product;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.geo.Distance;
import org.springframework.data.mongodb.core.geo.Metrics;
import org.springframework.data.mongodb.core.geo.Point;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Order;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;

/**
 * This class implements IAdvancedProductRepository methods.
 * 
 * @author juan_antonio
 * 
 */
@Repository
public class AdvancedRepository implements IAdvancedRepository {

    private final static Logger logger = LoggerFactory
	    .getLogger(AdvancedRepository.class);

    /**
     * Implements a basic set of MongoDB operations.
     */
    @Autowired
    MongoTemplate mongoTemplate;

    public List<Product> findBySubcategoryIn(List<String> subcategories) {
	Criteria criteria = new Criteria("subcategory").in(subcategories);
	Query query = new Query(criteria);
	return mongoTemplate.find(query, Product.class);
    }

    public List<Product> findBySubcategoryIn(List<String> subcategories,
	    int page, int size) {
	Criteria criteria = new Criteria("subcategory").in(subcategories);
	Query query = new Query(criteria).skip(page * size).limit(size);
	return mongoTemplate.find(query, Product.class);
    }

    public List<Product> findForSearch(String text, String status, List<String> subcategories,
	    String city, String locality, Double latitude, Double longitude,
	    Integer distance, int page, int size) {
	Query query = new Query();
	if (text != null) {
	    query.addCriteria(Criteria.where("title").regex(text, "i"));
	}
	if (status == null) {
	    status = Product.STATUS_PUBLISHED;
	}
	if (subcategories != null) {
	    query.addCriteria(Criteria.where("subcategory").in(subcategories));
	}
	if (city != null) {
	    query.addCriteria(Criteria.where("address.city").is(city));
	}
	if (locality != null) {
	    query.addCriteria(Criteria.where("address.locality").regex(
		    locality, "i"));
	}
	if (latitude != null && longitude != null && distance != null) {
	    double multiplier = Metrics.KILOMETERS.getMultiplier();
	    double maxDistance = distance / Metrics.KILOMETERS.getMultiplier();

	    logger.info("Distance (KM): " + distance + ", Multiplier: "
		    + multiplier + ", Calculated: " + maxDistance);

	    Point center = new Point(latitude, longitude);
	    query.addCriteria(Criteria.where("location").nearSphere(center)
		    .maxDistance(maxDistance));
	}
	query.addCriteria(Criteria.where("status").is(status));
	query.sort().on("publicationDate", Order.DESCENDING);
	query.skip(page * size).limit(size);

	return mongoTemplate.find(query, Product.class);
    }

    public List<Message> findMessagesBySenderNick(String nick, int page,
	    int size) {
	Query query = new Query();
	query.addCriteria(Criteria.where("sender.nick").is(nick));
	query.sort().on("date", Order.DESCENDING);
	query.skip(page * size).limit(size);
	return mongoTemplate.find(query, Message.class);
    }

    public List<Message> findMessagesByReceiverNick(String nick, int page,
	    int size) {
	Query query = new Query();
	query.addCriteria(Criteria.where("receiver.nick").is(nick));
	query.sort().on("date", Order.DESCENDING);
	query.skip(page * size).limit(size);
	return mongoTemplate.find(query, Message.class);
    }

    @Override
    public List<Product> findByLocation(Point point, Distance dist, int page,
	    int size) {

	return null;
    }

}
